/**
 *
 * カウントアップ用のタイマー
 *
 * @author takaratsunehito
 *
 */

/**
 * カウントアップタイマーの状態保存にGearsを使用するか
 */
CountupTimer.useGears = false;

/**
 * gearsで使用するデータベース名
 */
CountupTimer.dbName = 'all-in-one-timers';

/**
 * 状態保存用のデータベース名
 */
CountupTimer.tableName = "CountupTimers";

/**
 * gearsで使用するデータベースインスタンス
 */
CountupTimer.db = null;

/**
 * CountupTimerでGearsを利用できるように初期化する
 */
CountupTimer.initGears = function(){	
	if (window.google && google.gears) {
		try {
			CountupTimer.db = google.gears.factory.create('beta.database');
			if (CountupTimer.db) {
				CountupTimer.db.open(CountupTimer.dbName);
				
				/*
				 * データベースの作成
				 * title: タイマーのタイトル
				 * offset: オフセット
				 * start_time: カウントを始めた時刻(カウント中ではない場合 < 0)
				 * timestamp: タイマーの作成日時
				 */ 
				CountupTimer.db.execute('create table if not exists ' + CountupTimer.tableName + 
				' (title varchar(255), offset int, start_time int, timestamp int)');
				
				return;
			}
		} catch (ex) {
			
		}
		
		CountupTimer.useGears = false;
	}
}

/**
 * 前回閉じた際のタイマーの状態を復元する
 */
CountupTimer.restoreTimers = function (){
	var timers = new Array();
	
	if (CountupTimer.useGears) {
		var rs = CountupTimer.db.execute('select *,rowid from ' + CountupTimer.tableName + ' order by timestamp');
		while (rs.isValidRow()) {
			var id = rs.fieldByName("rowid");
			var title = rs.field(0);
			var offset = rs.field(1);
			var start_time = rs.field(2);
			
			var timer = CountupTimer.restoreTimer(id, title, start_time, offset);
			timers.push(timer);
			
			rs.next();
		}
		rs.close();
	} else {
        $.ajax({
            url: "list",
			async: false,
            cache: false,
			dataType: "json",
            success: function(json){
				for(var i = 0; i < json.length; i++) {
					var tmp = json[i].count_up_timer;
					var timer = CountupTimer.restoreTimer(tmp.id, tmp.title, tmp.start_time, tmp.offset);
					timers.push(timer);
				}
            }
        });
	}
	return timers;
}

CountupTimer.restoreTimer = function(id, title, start_time, offset){
	var timer = new CountupTimer(true);
	timer.id = id;
	if (title != "") {
		timer.titleElem.text(title);
	}
	if (start_time >= 0) {
		timer.offset = offset + (new Date().getTime() - start_time);
		timer.start(true);
	}
	else {
		timer.offset = offset;
	}
	timer.update();
	
	return timer;
}

/**
 * @param {Object} isRestore gearsによる状態復元用かどうか
 */
function CountupTimer(isRestore){　
	var timer = this;
    this.offset = 0;
	
	/*
	 * タイマー全体
	 */
	var timerElem = $('<div class="countup-timer"></div>');
	timerElem.data("timer", this);
    this.elem = timerElem;
	
	/*
	 * 簡易表示部分
	 */
	var subjectElem = $('<div class="subject"></div>');
	this.elem.append(subjectElem);
	
	/*
	 * タイマー選択・非選択状態表示部
	 */
	var selectedStateElem = $('<div class="selected-state">　</div>');
	this.selectedStateElem = selectedStateElem;
	subjectElem.append(selectedStateElem);
	
	/*
	 * 時間表示部分 
	 */
	var timeElem = $('<div class="time">00:00</div>');
	this.timeElem = timeElem;
	timeElem.click(function(){
		// クリックされた場合タイマーを止める
		timer.stop();
	});
	timeElem.editable(function(value, settings){
		// クリックされた場合、inputにする
		if(!value || value.length == 0){
			// valueがかららの場合もとの値を利用する
			return this.revert;
		}
		
		if(this.revert != value) {
			// 値が変更された場合
			var milisec = CountupTimer.parseTimeStr(value);
			if(isNaN(milisec)){
				return this.revert;
			}
			timer.setTime(milisec);
			return timer.toString();
		}
		return value;
	},{
		// チェック機能ありのinputフィールドを使用
		type: 'checked-text',
		onblur: 'submit',
		checkfunc: function(){ // 入力チェック
			var milisec = CountupTimer.parseTimeStr($(this).val());
			if(isNaN(milisec)) {
				$(this).css("background-color", "LightPink");
			} else {
				$(this).css("background-color", "white");
			}
		}
	});
	subjectElem.append(timeElem);	
    
	/*
	 * タイトル部分
	 */
	var titleElem = $('<div class="title"></div>');
	this.titleElem = titleElem;
	titleElem.editable(function(value, settings){
		value = jQuery.trim(value)
        if (this.revert != value) {
            $(this).text(value);
            timer.log("タイトルを「" + value + "」へ変更。");
			
			if (CountupTimer.useGears) {
				// TODO SQLインジェンクション対応必要
				CountupTimer.db.execute("UPDATE " + CountupTimer.tableName + " SET title='" + value + "' where rowid=" + timer.id);
			}
        }
        return value;
    }, {
        type: 'text',
        onblur: 'submit',
        width: '290px'
    });
	subjectElem.append(titleElem);
	
	/*
	 * start、stopを切り替えるボタン
	 */
	var toggleButton = $('<img src="/images/start-button.gif" class="toggle-button"/>');
	this.toggleButton = toggleButton;
	toggleButton.click(function(){
		timer.toggle();
	});
	subjectElem.append(toggleButton);
	
	/*
	 * リセットボタン
	 */
	var resetButton = $('<img src="/images/reset-button.gif" class="reset-button" />');
	resetButton.click(function(){
		timer.reset();
	});
	subjectElem.append(resetButton);
	
	/*
	 * タイマー削除ボタン
	 */
	var deleteButton = $('<img src="/images/delete-button.gif" class="delete-button" alt="[x]" />');
	deleteButton.click(function(){
		timer.remove();	
	});
	subjectElem.append(deleteButton);
	
	/*
	 * ログ表示部
	 * (ログ表示・非表示部で必要なので先に作成)
	 */
	var logElem = $('<div class="log" style="display: none"></div>');
	this.logElem = logElem;
	
	/*
	 * ログ表示・非表示切り替え部
	 */
	var toggleLogElem = $('<div class="toggle-log-display">▲ログを表示</div>');
	toggleLogElem.click(function(){
        if (jQuery.trim(logElem.css("display")) == "none") {
            logElem.show("normal", function(){
                toggleLogElem.text("▼ログを非表示");
            });
        }
        else {
            logElem.hide("normal", function(){
                toggleLogElem.text("▲ログを表示");
            });
        }
	});
	timerElem.append(toggleLogElem);
	timerElem.append(logElem);
	
	/*
	 * タイマー追加後すぐにタイトル部分へフォーカスする
	 */
	if (!isRestore) {
		timerElem.hide();
		setTimeout(function(){
			timerElem.show(0);
			titleElem.click();
		}, 0);
		this.log("タイマー作成");
		if (CountupTimer.useGears) {
			CountupTimer.db.execute('insert into ' + CountupTimer.tableName + ' values (?, ?, ?, ?)', ["", 0, -1, new Date().getTime()]);
			this.id = CountupTimer.db.lastInsertRowId;
		}
	} else {
		this.log("タイマー復元");
	}
};

/**
 * タイマー部への入力をパースし、ミリ秒へ変換。
 * 適切な値・形式でない場合、Number.NaNを返す。
 * 
 * @param {String} timeStr タイマー部へ入力値
 */
CountupTimer.parseTimeStr = function(timeStr){
	var timeStrs = timeStr.split(":");
	
	// コロンが３つ以上ある場合
    if (timeStrs.length > 3) {
		return Number.NaN;
    }
    
    var offset = 0;
    var multiplier = 1;
    for (var i = timeStrs.length - 1; i >= 0; i--) {
        var num = new Number(timeStrs[i]);
		
		//数字ではない場合およびマイナスの場合
        if (isNaN(num) || num < 0) {
        	return Number.NaN;
		}
        
        offset += multiplier * num;
        multiplier *= 60;
    }
	return offset * 1000;
}

CountupTimer.prototype = {
	/**
	 * 
	 */
    getElem: function(){
        return this.elem;
    },
    
	/**
	 * タイマーの初期値を設定する
	 * @param {Number} offset タイマーの初期値(ミリ秒)
	 */
    setTime: function(offset){
        this.offset = offset;
		var str = this.toString();
		this.timeElem.text(str);
		this.log("タイマーを " + str + "へ変更。");
		
		if (CountupTimer.useGears) {
			CountupTimer.db.execute("UPDATE " + CountupTimer.tableName + " SET offset=" + offset + " where rowid=" + this.id);
		}
    },
    
	/**
	 * 表示のアップデート
	 */
    update: function(){
      	this.timeElem.text(this.toString());
    },
	
	/**
	 * 時間の文字列表示
	 */
	toString: function(){
		var now = new Date().getTime();
        var count = this.isStoped() ? Math.floor(this.offset / 1000) : Math.floor((now - this.start_time + this.offset) / 1000);
        var hour = Math.floor(count / (60 * 60));
        var minute = Math.floor(count / 60 % 60);
        var second = count % 60;
        
        if (hour == 0) {
            return "%02.0d:%02.0d".sprintf(minute, second);
        }
        else {
            return "%02.0d:%02.0d:%02.0d".sprintf(hour, minute, second);
        }
	},
    
	/**
	 * タイマーの削除
	 */
    remove: function(){
        this.stop();

		if (this.isSelected) {
			// 選択状態の解除を通知
			unselectTimer();
		}

        this.elem.remove();
		
		if(CountupTimer.useGears){
			CountupTimer.db.execute("delete from " + CountupTimer.tableName + " where rowid=" + this.id);
		}
    },
    
	/**
	 * タイマーのスタート・ストップのきり合え
	 */
    toggle: function(){
        if (this.isStoped()) {
            this.start();
        }
        else {
            this.stop();
        }
    },
    
	/**
	 * カウントアップの開始
	 * @param {Object} isRestore gearsによる状態復元用かどうか
	 */
    start: function(isRestore){
        var updateFunction = function(obj){
            return function(){
                obj.update();
            }
        };
        this.interval_id = setInterval(updateFunction(this), 500);
        
        this.start_time = new Date().getTime();
        
        this.toggleButton.attr("src", "/images/stop-button.gif");
        
		if (!isRestore) {
			this.log("カウントアップ開始");
			if (CountupTimer.useGears) {
				CountupTimer.db.execute("UPDATE " + CountupTimer.tableName + " SET offset=" + this.offset + ", start_time=" + this.start_time + " where rowid=" + this.id);
			}
		}
    },
    
	/**
	 * カウントアップの一時停止
	 */
    stop: function(){
    	if(this.interval_id){
	        clearInterval(this.interval_id);
	        this.interval_id = null;
	        
	        // 現在のカウントの値を保存
	        var now = new Date().getTime();
	        this.offset = now - this.start_time + this.offset;
	        this.start_time = -1;
			
	        this.toggleButton.attr("src", "/images/start-button.gif");
	        
	        this.log("カウントアップ停止");
			if (CountupTimer.useGears) {
				CountupTimer.db.execute("UPDATE " + CountupTimer.tableName + " SET offset="  + this.offset +  ", start_time=-1 where rowid=" + this.id);
			}
    	}
    },
    
	/**
	 * カウントアップのリセット
	 */
    reset: function(){
		if (!this.isStoped()) {
			this.start_time = new Date().getTime();
		}　else {
			this.start_time = -1;
		}
		this.offset = 0;
		
		this.timeElem.text("00:00");
		
		this.log("リセット");
		
		if (CountupTimer.useGears) {
			CountupTimer.db.execute("UPDATE " + CountupTimer.tableName + " SET offset=0, start_time=" + this.start_time + " where rowid=" + this.id);
		}
    },
    
	/**
	 * カウントアップが一時停止されてるか
	 */
    isStoped: function(){
        return !this.interval_id;
    },
    
	/**
	 * 呼び出された日時と引数に与えれたログの詳細をログに残すl。
	 * 
	 * @param {Object} logStr ログの詳細
	 */
    log: function(logStr){
        var dateformat = new DateFormat("yyyy/MM/dd HH:mm:ss");
        this.logElem.prepend("<div>" + dateformat.format(new Date) + ":" + logStr + "</div>");
    },

	/**
	 * タイマーを選択
	 */
	select : function(){
		this.isSelected = true;
		this.selectedStateElem.text(">");
	
		//TODO 自分が表示されるようにスライドさせる必要あり
	},
	
	/**
	 * タイマーの選択を解除
	 */
	unselect : function(){
		this.isSelected = false;
		this.selectedStateElem.text("　");
	},

	/**
	 * キーショートカット
	 * @param {Object} e キーイベント
	 */
	shortcut : function(e){
		switch(e.which){
			case 116:
			// t
			this.titleElem.click();
			break;
			
			case 114:
			// r
			this.reset();
			break;
			
			case 8:
			// backspace
			this.remove();
			break;
			
			case 13:
			// Enter
			this.toggle();
		}
	}
};
